package com.radar.controller;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.radar.algorithm.MathCommon;
import com.radar.common.DateConstants;
import com.radar.common.GisConstants;
import com.radar.common.ProductType;
import com.radar.io.CinradRadar;
import com.radar.io.RadarGridData;
import com.radar.model.ResultBody;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import org.geotools.geojson.feature.FeatureJSON;
import org.opengis.feature.simple.SimpleFeature;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;

@Api(tags = "warning controller")
@RestController
@RequestMapping("warning")
@Slf4j
public class WarningController {

    @PostMapping("getWarningData")
    public ResultBody getData(@RequestBody String parm) {
        JsonObject parmJson = (JsonObject) new JsonParser().parse(parm);
        JsonArray parse = parmJson.get("threshold").getAsJsonArray();
        JsonObject 机场中心点 = parmJson.get("airport").getAsJsonObject();
        String obsTime = parmJson.get("obs_time").getAsString();
        long time = System.currentTimeMillis();
        HashMap<String, RadarGridData> allGridData = getAllGridData(parse, obsTime);
        if (allGridData == null){
            return ResultBody.ok().data(new Gson().toJson(parse));
        }
        warning(parse, allGridData, 机场中心点, obsTime);

        return ResultBody.ok().data(new Gson().toJson(parse));
    }

    public void warning(JsonArray parse, HashMap<String, RadarGridData> allGridData, JsonObject 机场中心点, String obsTime) {
        for (int i = 0; i < parse.size(); i++) {
            JsonObject asJsonObject = parse.get(i).getAsJsonObject();
            List<HashMap<String, String>> maps = warningItem(asJsonObject.get("rules").getAsJsonArray(), asJsonObject, allGridData, transferGEO(asJsonObject), 机场中心点, obsTime);
            if (maps != null && maps.size() > 0) {
                asJsonObject.add("warnings", new JsonParser().parse(new Gson().toJson(maps, new TypeToken<ArrayList<HashMap<String, String>>>() {
                }.getType())));
            }
        }
    }

    public List<HashMap<String, String>> warningItem(JsonArray array, JsonObject obj, HashMap<String, RadarGridData> allGridData, Geometry geometry, JsonObject 机场中心点, String obsTime) {
        List<HashMap<String, String>> errors = new ArrayList<>();
        double x = 机场中心点.get("lonlat").getAsJsonArray().get(0).getAsDouble();
        double y = 机场中心点.get("lonlat").getAsJsonArray().get(1).getAsDouble();

        String 告警name = obj.get("name").getAsString();
        if (geometry == null) {
            return null;
        }
        if (geometry.getClass() == LineString.class || geometry.getClass() == MultiLineString.class || geometry.getClass() == Point.class) {
            // 10km 缓冲区
            geometry = geometry.buffer(0.1);
        }
        for (int z = 0; z < array.size(); z++) {
            String code = array.get(z).getAsJsonObject().get("type").getAsString();
            String name = array.get(z).getAsJsonObject().get("name").getAsString();
            if (!array.get(z).getAsJsonObject().get("isOpen").getAsBoolean()) {
                continue;
            }
            if (!allGridData.containsKey(code)) {
                continue;
            }
            String s1 = array.get(z).getAsJsonObject().get("yellow").getAsJsonArray().get(0).getAsString();
            String s2 = array.get(z).getAsJsonObject().get("yellow").getAsJsonArray().get(1).getAsString();
            String s3 = array.get(z).getAsJsonObject().get("red").getAsJsonArray().get(0).getAsString();
            String s4 = array.get(z).getAsJsonObject().get("red").getAsJsonArray().get(1).getAsString();
            double yellowmin = s1.equals("") ? Double.MAX_VALUE : Double.parseDouble(s1);
            double yellowmax = s2.equals("") ? Double.MIN_VALUE : Double.parseDouble(s2);
            double redmin = s3.equals("") ? Double.MAX_VALUE : Double.parseDouble(s3);
            double redmax = s4.equals("") ? Double.MIN_VALUE : Double.parseDouble(s4);

            boolean iserror = false;
            String errorcode = "";
            RadarGridData gridData = allGridData.get(code);
            double distince = Double.MAX_VALUE;
            double 最大值 = Double.MIN_VALUE;
            int 命中点 = 0;
            int index = 0;
            double[][] caclvalues = gridData.caclData != null ?MathCommon.decodeCal(gridData.caclData) : null;
            for (int i = 0; i < gridData.getYNum(); i++) {
                for (int j = 0; j < gridData.getXNum(); j++) {
                    GeometryFactory geometryFactory = new GeometryFactory();
                    Coordinate point = new Coordinate(gridData.xArray[j],gridData.yArray[i]);
                    if (!geometry.contains(geometryFactory.createPoint(point))) {
                        index++;
                        continue;
                    }
                    double a = GisConstants.UNDEF;
                    if (code.equals("REF")) {
                        a = MathCommon.Decode(gridData.radarData[i][j], ProductType.REF);
                    } else if (code.equals("ET")) {
                        a = caclvalues[i][j];
                    }
                    // 命中

                    if (a > redmin && a < redmax) {
                        iserror = true;
                        errorcode = " 红色告警";

                        double dis = MathCommon.getDistanceKM(point.x, x, point.y, y);
                        if (distince > dis) {
                            distince = dis;
                        }

                        命中点++;
                    }
                    if (a > yellowmin && a < yellowmax) {
                        iserror = true;
                        errorcode = errorcode.equals("") ? "黄色告警" : errorcode;
                        命中点++;
                        double dis = MathCommon.getDistanceKM(point.x, x, point.y, y);
                        if (distince > dis) {
                            distince = dis;
                        }
                    }
                    index++;
                }
            }

            if (iserror) {
                int final命中点 = 命中点;
                java.text.DecimalFormat df = new java.text.DecimalFormat("0.00");
                String finalErrorcode = 告警name + ": 发生 " + name + errorcode + "; 到达本场距离: " + df.format(distince) + "km; ";
                errors.add(new HashMap<String, String>() {{
                    put("击中点", final命中点 + "");
                    put("告警文本", finalErrorcode);
                    put("color", finalErrorcode.contains("黄色") ? "yellow" : "red");
                    put("数据时间", obsTime + "");
                }});
            }
        }
        return errors;
    }

    @Autowired
    private RadarController radarController;

    private String processPath;

    //    private String radarcode = "Z9002";
    @Value("${radar.radar-station:''}")
    private String radarcode;


    @Value("${radar.process-path:''}")
    public void setProcessPath(String processPath) {
        this.processPath = processPath;
    }

    public HashMap<String, RadarGridData> getAllGridData(JsonArray parse, String obsTime) {
        HashMap<String, RadarGridData> allgriddata = new HashMap<>();
        List<Geometry> geometries = transferGEO(parse);
        List<Double> xarray = new ArrayList<>();
        List<Double> yarray = new ArrayList<>();
        geometries.stream().forEach(i -> Arrays.stream(i.getCoordinates()).forEach(z -> {
            xarray.add(z.x);
            yarray.add(z.y);
        }));
//        HashMap<String, Object> timeLine = radarController.getTimeLine(null);
//        String obsTime = ((List<Map<String, String>>) timeLine.get("data")).get(((List<Map<String, String>>) timeLine.get("data")).size() - 1).get("timestamp");
        CinradRadar cinradRadar = null;
        try {
            if (StringUtils.isBlank(obsTime)) {
                return null;
            }
            Date dt = DateUtil.parse(obsTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
            String realPath = this.processPath + File.separator + DateUtil.format(dt, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(dt, DateConstants.DATE_FORMAT_YYYYMMDDHHMM) + File.separator;
            List<File> files = FileUtil.loopFiles(realPath, new RegexFileFilter("^Z_RADR_I_Z(\\d{4})_(\\d{14})_O_DOR_(.*?)_CAP_FMT.(BIN.BZ2|bin.bz2|bin)$"));
            if (files == null || files.size() != 1) {
                return null;
            }
            cinradRadar = new CinradRadar();
            // TODO 修改自定义站点
            if (radarcode.equals("")) {
                cinradRadar.parse(files.get(0).getAbsolutePath());
            } else {
                cinradRadar.parse(files.get(0).getAbsolutePath(), null, radarcode);
            }
            cinradRadar.radar.setProjectStep(0.02);
        } catch (Exception e) {
            e.printStackTrace();
        }
        CinradRadar finalCinradRadar = cinradRadar;
        parse.forEach(i -> {
            i.getAsJsonObject().get("rules").getAsJsonArray().forEach(z -> {
                String code = z.getAsJsonObject().get("type").getAsString();
                if (!allgriddata.containsKey(code) && z.getAsJsonObject().get("isOpen").getAsBoolean()) {
                    try {
                        if (code.equals("REF")) {
                            allgriddata.put(code, finalCinradRadar.radar.getCR());
                        } else if (code.equals("ET")) {
                            allgriddata.put(code, finalCinradRadar.radar.getET());
                        }
                    } catch (Exception e) {
                        finalCinradRadar.radar.close();
                        e.printStackTrace();
                    }

                }
            });
        });
        finalCinradRadar.radar.close();
        return allgriddata;
    }

    public List<Geometry> transferGEO(JsonArray parse) {
        List<Geometry> list = new ArrayList<>();
        parse.forEach(i -> {
            Geometry geometry = transferGEO(i.getAsJsonObject());
            if (geometry != null) {
                list.add(geometry);
            }
        });
        return list;
    }

    public Geometry transferGEO(JsonObject obj) {
        String geojson = obj.get("geo").getAsString();
        FeatureJSON featureJSON = new FeatureJSON();
        try {
            SimpleFeature geo = featureJSON.readFeature(new StringReader(JSON.parse(geojson).toString()));
            return (Geometry) geo.getDefaultGeometry();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}















